#ifndef VD_CHECK_FILE
#define VD_CHECK_FILE

# include "vd.h"
# include "VD_Crypto.h"

NTSTATUS VD_CheckFile (
					IN PDEVICE_OBJECT   DeviceObject,
					IN PIRP Irp)
{

	NTSTATUS						status;
	PDEVICE_EXTENSION               device_extension;
	LONG							PasswordLen;	
	PULONG							CryptedPassword;
	LONG							Tmp;
	PIO_STACK_LOCATION				io_stack;
	LARGE_INTEGER					ByteOffset;
	PULONG							Char2Long;
	UCHAR							Char2LongBuffer[MAXIMUM_FILENAME_LENGTH];
	LONG							AlignedPassLen;
	USHORT							i;	
	USHORT							j;
	PUCHAR							DecryptedPassword;


	device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
	
	io_stack = IoGetCurrentIrpStackLocation(Irp);
	
	if (device_extension->IsDiskRaw == TRUE){
	
		if ((device_extension->pas_len & 7) != 0)
			PasswordLen = (device_extension->pas_len | 7) + 1 + LONGSIZE;
		else	
			PasswordLen = device_extension->pas_len + LONGSIZE;
	
		CryptedPassword = (PULONG)ExAllocatePoolWithTag(
													NonPagedPool,
													DiskIdentificationLen + PasswordLen + LONGSIZE,
													POOL_TAG
													);
		if (CryptedPassword == NULL)
        {
			DbgPrint("Unable to allocate memory for CryptedPassword \n");
			Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
            return STATUS_INSUFFICIENT_RESOURCES;    
        }

		RtlCopyMemory(
					Char2LongBuffer,
					device_extension->password,
					device_extension->pas_len					
					);
		Char2LongBuffer[PasswordLen - 1] = '\0';
	
		Char2Long = (ULONG*)DiskIdentification;
				
		for (i = 0; i < DiskIdentificationLen/LONGSIZE; i+=2){
			CryptedPassword[i] = *(Char2Long + i);
			CryptedPassword[i + 1] = *(Char2Long + i + 1);
			
			VD_BF_Encrypt(&device_extension->ctx,&CryptedPassword[i], &CryptedPassword[i+1]);
		}

		Char2Long = (ULONG*) Char2LongBuffer;
		
		CryptedPassword[LONGSIZE] = device_extension->pas_len;
	
		for (i = LONGSIZE; i < (DiskIdentificationLen + PasswordLen - LONGSIZE)/LONGSIZE; i+=2)
		{
			CryptedPassword[i+1] = 	*(Char2Long + i - LONGSIZE);	
			CryptedPassword[i+2] = *(Char2Long + i + 1 - LONGSIZE);
			VD_BF_Encrypt(&device_extension->ctx,&CryptedPassword[i+1], &CryptedPassword[i+2]);
		}
  
		ByteOffset.QuadPart = 0i64; 
		io_stack->Parameters.Write.ByteOffset = ByteOffset;

		status = ZwWriteFile(
						  device_extension->file_handle,
						  NULL,
						  NULL,
						  NULL,
						  &Irp->IoStatus,
						  (PVOID*)CryptedPassword,
						  PasswordLen + DiskIdentificationLen,
					      &io_stack->Parameters.Write.ByteOffset,
						  NULL
							);
		
		if (!NT_SUCCESS(status)){
			DbgPrint("Unable to write password to file %x \n", status);
			Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
            return STATUS_UNSUCCESSFUL;    
		}
				
		DbgPrint("Write Password to file \n");
		ExFreePoolWithTag(CryptedPassword,POOL_TAG);
	}
	
	else{
		
		if ((device_extension->enc_pass_len & 7) != 0)
			AlignedPassLen = (device_extension->enc_pass_len | 7) + 1;
		else
		   AlignedPassLen = device_extension->enc_pass_len;
		
		CryptedPassword = (PULONG)ExAllocatePoolWithTag(
													NonPagedPool,
													AlignedPassLen + LONGSIZE,
													POOL_TAG
													);

		if (CryptedPassword == NULL)
        {
			DbgPrint("Unable to allocate memory for CryptedPassword \n");
			Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
            return STATUS_INSUFFICIENT_RESOURCES;    
        }

		ByteOffset.QuadPart = LONGSIZE + DiskIdentificationLen; 
		io_stack->Parameters.Read.ByteOffset = ByteOffset;

		status = ZwReadFile(
						  device_extension->file_handle,
						  NULL,
						  NULL,
						  NULL,
						  &Irp->IoStatus,
						  (PVOID*)CryptedPassword,
						  AlignedPassLen,
					      &io_stack->Parameters.Read.ByteOffset,
						  NULL
							);
		
		if (!NT_SUCCESS(status)){
			
			DbgPrint("Unable to allocate memory for CryptedPassword \n");
			Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
            return STATUS_UNSUCCESSFUL;    
		}

		for (i = 0; i < AlignedPassLen/LONGSIZE; i+=2)
		{	
			VD_BF_Decrypt(&device_extension->ctx,&CryptedPassword[i], &CryptedPassword[i+1]);
		}
		DecryptedPassword = (PUCHAR)ExAllocatePoolWithTag(
													NonPagedPool,
													device_extension->enc_pass_len + 1,
													POOL_TAG
													);
		if (DecryptedPassword == NULL)
        {
			DbgPrint("Unable to allocate memory for DecryptedPassword \n");
			Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
            return STATUS_UNSUCCESSFUL;    
        }

		RtlCopyMemory(
					DecryptedPassword,
					CryptedPassword,
					device_extension->enc_pass_len
					);
		DecryptedPassword[device_extension->enc_pass_len] = '\0';
		if (device_extension->enc_pass_len == device_extension->pas_len)
		{
			device_extension->PasswordCheck = RtlEqualMemory(
														device_extension->password, 
														DecryptedPassword,
														device_extension->pas_len);	
		}
		else
			device_extension->PasswordCheck = 0;
	}

	return status;
}	

#endif